﻿using FB.Data;
using FB.Data.Models;
using FB.Enums;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Net;

namespace FB.Providers.AEInfo
{
    public class AEInfoUnit : UnitOfWorkBase<AEDbContext>
    {
        Hashtable _repositories;

        internal AEInfoUnit(AEDbContext context) : base(context) { }

        public AERepository<T> Repository<T>() where T : class
        {
            if (_repositories == null)
                _repositories = new Hashtable();

            var type = typeof(T).Name;

            if (!_repositories.ContainsKey(type))
            {
                var repositoryType = typeof(AERepository<>);

                var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), _context);
                _repositories.Add(type, repositoryInstance);
            }

            return (AERepository<T>)_repositories[type];
        }


        public bool SetClientLocation(string ClientCode, int? LocationID)
        {
            var result = false;
            Location location = null;
            if (LocationID.HasValue)
                location = Repository<Location>().GetByKey(LocationID.Value);

            var detail = Repository<ClientDetail>().GetByKey(ClientCode);

            if (detail != null && (!LocationID.HasValue || (LocationID.HasValue && location != null)))
            {
                detail.LocationID = LocationID;

                Repository<ClientDetail>().Update(detail);

                #region History

                var history = new ClientAllocationHistory
                {
                    ClientCode = detail.ClientCode,
                    EffectiveDate = DateTime.Now
                };

                if (location != null)
                {
                    history.BCHCode = location.BCHCode;
                    history.Room = location.Room;
                    history.Seat = location.Seat;
                    if (location.RoomSize != null)
                        history.RoomSize = location.RoomSize.Size;
                }

                Repository<ClientAllocationHistory>().Insert(history);

                #endregion

                result = SaveChanges() > 0;
            }

            return result;
        }


        public bool SetLocation(long AEDetailID, int? LocationID)
        {
            var result = false;

            Location location = null;
            if (LocationID.HasValue)
                location = Repository<Location>().GetByKey(LocationID.Value);

            var detail = Repository<AEDetail>().GetByKey(AEDetailID);

            if (detail != null && (!LocationID.HasValue || (LocationID.HasValue && location != null)))
            {
                detail.LocationID = LocationID;

                Repository<AEDetail>().Update(detail);

                #region History

                var history = new AllocationHistory
                {
                    AEID = detail.ID,
                    EffectiveDate = DateTime.Now
                };

                if (location != null)
                {
                    history.BCHCode = location.BCHCode;
                    history.Room = location.Room;
                    history.Seat = location.Seat;
                    if (location.RoomSize != null)
                        history.RoomSize = location.RoomSize.Size;
                }

                Repository<AllocationHistory>().Insert(history);

                #endregion

                result = SaveChanges() > 0;
            }

            return result;
        }


        #region AECode Management

        public bool AttachAECode(long AEDetailID, string AECode, AEMappingType? MappingType)
        {
            var result = false;
            var d = (from a in Repository<AEBaseInfo>().Get()
                     where a.AECode == AECode && a.DetailID == null
                     select a).FirstOrDefault();

            if (d != null)
            {
                d.DetailID = AEDetailID;
                d.MappingType = MappingType;

                #region create history

                var history = new AEMappingHistory
                {
                    AECode = AECode,
                    DetailID = AEDetailID,
                    MappingType = MappingType,
                    EffectiveDate = DateTime.Now,
                };

                Repository<AEMappingHistory>().Insert(history);

                #endregion

                result = SaveChanges() > 0;
            }

            return result;
        }

        public bool DetachAECode(long AEDetailID, string AECode)
        {
            var result = false;
            var d = (from a in Repository<AEBaseInfo>().Get()
                     where a.AECode == AECode && a.DetailID == AEDetailID
                     select a).FirstOrDefault();

            if (d != null)
            {
                d.DetailID = null;
                d.MappingType = null;

                #region create history

                var history = new AEMappingHistory
                {
                    AECode = AECode,
                    EffectiveDate = DateTime.Now,
                };

                Repository<AEMappingHistory>().Insert(history);

                #endregion

                result = SaveChanges() > 0;
            }

            return result;
        }


        public bool SyncAECode(long AEDetailID, Dictionary<string, AEMappingType?> MappingInfo)
        {
            var UpdateCount = 0;
            var ExCode = GetAECode(AEDetailID).ToList();

            #region create history
            Action<long?, string, AEMappingType?> CreateHistory = (AEID, AEC, MapType) =>
            {
                var h = new AEMappingHistory
                {
                    DetailID = AEID,
                    AECode = AEC,
                    MappingType = MapType,
                    EffectiveDate = DateTime.Now,
                };

                Repository<AEMappingHistory>().Insert(h);
            };
            #endregion

            #region step 1: Remove AEcode
            foreach (var ec in ExCode)
            {
                if (!MappingInfo.ContainsKey(ec.AECode))
                {
                    var oc = Repository<AEBaseInfo>().Get(w => w.DetailID == AEDetailID && w.AECode == ec.AECode).FirstOrDefault();
                    if (null != oc)
                    {
                        oc.DetailID = null;
                        oc.MappingType = null;
                        Repository<AEBaseInfo>().Update(oc);
                        CreateHistory(null, ec.AECode, null);
                        UpdateCount++;
                    }
                }
            }
            #endregion

            if (MappingInfo.Count() > 0)
            {
                foreach (var mi in MappingInfo)
                {
                    var oc = Repository<AEBaseInfo>().Get(w => w.DetailID == AEDetailID && w.AECode == mi.Key).FirstOrDefault();
                    if (oc != null)
                    {
                        #region Update
                        if (oc.MappingType != mi.Value)
                        {
                            oc.MappingType = mi.Value;
                            Repository<AEBaseInfo>().Update(oc);
                            CreateHistory(AEDetailID, mi.Key, mi.Value);
                            UpdateCount++;
                        }
                        #endregion
                    }
                    else
                    {
                        #region Create New
                        Repository<AEBaseInfo>().Update(new AEBaseInfo { DetailID = AEDetailID, AECode = mi.Key, MappingType = mi.Value });
                        CreateHistory(AEDetailID, mi.Key, mi.Value);
                        #endregion
                        UpdateCount++;
                    }
                }
            }

            if (UpdateCount > 0)
            {
                return SaveChanges() > 0;
            }

            return false;
        }


        public bool UpdateAECode(long AEDetailID, string AECode, AEMappingType? MappingType)
        {
            var r = false;

            var d = (from a in Repository<AEBaseInfo>().Get()
                     where a.AECode == AECode && a.DetailID == AEDetailID && a.MappingType != MappingType
                     select a).FirstOrDefault();

            if (d != null)
            {
                d.DetailID = AEDetailID;
                d.MappingType = MappingType;

                #region create history

                var history = new AEMappingHistory
                {
                    AECode = AECode,
                    DetailID = AEDetailID,
                    MappingType = MappingType,
                    EffectiveDate = DateTime.Now,
                };

                Repository<AEMappingHistory>().Insert(history);

                #endregion

                r = SaveChanges() > 0;
            }

            return r;
        }


        public AEBaseInfo GetAECodeOwner(string AECode)
        {
            return Repository<AEBaseInfo>().Get(w => w.AECode == AECode).FirstOrDefault();
        }

        public IQueryable<AEBaseInfo> GetAECode(long AEID)
        {
            return Repository<AEBaseInfo>().Get().Where(w => w.DetailID == AEID);
        }

        #endregion

        public IQueryable<AEDetail> FindAEDetailByName(string Name)
        {
            return Repository<AEDetail>().Get(w => (w.LastName + " " + w.FirstName + " " + w.Alias + " " + w.ChineseName).Trim().Contains(Name));
        }

        public AEDetail GetAEDetail(long ID)
        {
            return Repository<AEDetail>().GetByKey(ID);
        }


    }

    public class AERepository<TEntity> : Repository<AEDbContext, TEntity> where TEntity : class
    {
        public AERepository(AEDbContext context) : base(context) { }
    }

    
    
}
